package demo.lock;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author Arnold Yand
 * @since Mar 9, 20178:25:45 PM
 * @summary demo.lock.ReentrantLockDemo.java
 */
public class LockVsSynchronizedDemo {

    public LockVsSynchronizedDemo() {
        // Synchronized VS Lock
        performanceCompare();
        // performance for using Synchronized. init value of count = 0
        // result value of count = 500000000, and cost:49 seconds
        // =====================================
        // performance for using Lock. init value of count = 0
        // result value of count = 500000000, and cost:28 seconds
        // seems Lock is better.
    }

    public static void main(String[] args) {
        new LockVsSynchronizedDemo();
    }

    public void performanceCompare() {
        final int threadCount = 10;
        final int loopCount = 50000000;
        final Resources res1 = new Resources();
        System.out.println("performance for using Synchronized. init value of count = " + res1.getCount());
        ExecutorService executor = Executors.newFixedThreadPool(threadCount);
        long startTime = System.currentTimeMillis();
        for (int i = 0; i < threadCount; i++) {
            executor.execute(new Runnable() {
                @Override
                public void run() {
                    for (int i = 0; i < loopCount; i++) {
                        res1.incCountWithSynchronized();
                    }
                }
            });
        }
        try {
            executor.shutdown();
            executor.awaitTermination(60, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
        }
        long endTime = System.currentTimeMillis();
        System.out.println("result value of count = " + res1.getCount() + ", and cost:" + (endTime - startTime) / 1000 + " seconds");

        System.out.println("=====================================");
        final Resources res2 = new Resources();
        System.out.println("performance for using Lock. init value of count = " + res2.getCount());
        executor = Executors.newFixedThreadPool(threadCount);
        startTime = System.currentTimeMillis();
        for (int i = 0; i < threadCount; i++) {
            executor.execute(new Runnable() {
                @Override
                public void run() {
                    for (int i = 0; i < loopCount; i++) {
                        res2.incCountWithLock();
                    }
                }
            });
        }
        try {
            executor.shutdown();
            executor.awaitTermination(60, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
        }
        endTime = System.currentTimeMillis();
        System.out.println("result value of count = " + res1.getCount() + ", and cost:" + (endTime - startTime) / 1000 + " seconds");

    }

    private class Resources {
        private int count = 0;
        private Lock lock = new ReentrantLock();

        public Resources() {
        }

        public int getCount() {
            return count;
        }

        public int incCountWithSynchronized() {

            synchronized (lock) {
                count += 1;
                return count;
            }
        }

        public int incCountWithLock() {
            try {
                lock.lock();
                count += 1;
                return count;
            } finally {
                lock.unlock();
            }
        }
    }

}
